import numpy as np
import os, sys

# 将当前目录添加到Python路径中，确保可以导入同目录下的模块
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

# 从动作编码器模块导入智能体JSON到本地属性的映射
from action_set_encoder import agent_json2local_attrs


class Agent(object):
    """
    智能体类：表示游戏中的一个智能体单位

    这个类封装了智能体的所有属性和行为，包括位置、速度、生命值等。
    智能体可以是玩家控制的单位、AI控制的单位等。
    """

    def __init__(self, team, team_id, uid, location, rotation, velocity, health, yaw, speed) -> None:
        """
        初始化智能体对象

        Args:
            team (int): 智能体所属的队伍编号（如0代表红队，1代表蓝队）
            team_id (int): 智能体在队伍中的ID编号
            uid (int): 智能体的全局唯一标识符
            location (tuple): 智能体的3D位置坐标 (x, y, z)
            rotation (tuple): 智能体的3D旋转角度 (x, y, z)
            velocity (tuple): 智能体的3D速度向量 (x, y, z)
            health (float): 智能体的当前生命值
            yaw (float): 智能体的偏航角（水平旋转角度）
            speed (float): 智能体的最大移动速度
        """
        # 初始化位置为None，将在后面设置
        self.location = None

        # 基本信息
        self.team = team                    # 队伍编号
        self.team_id = team_id              # 队伍内ID
        self.uid = uid                      # 全局唯一标识符

        # 获取JSON到本地属性的映射配置
        self.attrs = agent_json2local_attrs

        # 根据映射配置动态设置所有智能体属性，初始值设为None
        # 这一步确保智能体对象拥有所有必要的属性，即使初始值为空
        for attr_json, attr_agent in self.attrs:
            setattr(self, attr_agent, None)

        # 设置核心属性值
        self.location = location            # 3D位置坐标
        self.velocity = velocity            # 3D速度向量
        self.rotation = rotation            # 3D旋转角度
        self.max_speed = speed              # 最大移动速度

        # 创建位置向量的不同表示形式，便于不同场景下的计算
        self.pos3d = np.array([location[0], location[1], location[2]])  # 3D位置向量
        self.pos2d = np.array([location[0], location[1]])              # 2D位置向量（只取x,y坐标）

        # 创建速度向量的不同表示形式
        self.vel3d = np.array([velocity[0], velocity[1], velocity[2]])  # 3D速度向量

        # 基本战斗属性
        self.hp = health                    # 当前生命值
        self.yaw = yaw                      # 偏航角（水平旋转角度）
        self.speed = speed                  # 最大移动速度

        # 注释掉的代码：2025年7月的更新，现在从JSON数据中获取位置信息
        # self.pos3d = np.array([np.nan, np.nan, np.nan])  # 之前用于初始化NaN位置
        # self.pos2d = np.array([np.nan, np.nan])          # 之前用于初始化NaN位置

    def update_agent_attrs(self, dictionary):
        """
        根据游戏引擎提供的JSON数据更新智能体的所有属性

        这个方法是智能体与环境交互的核心，它将游戏引擎的状态信息
        同步到智能体对象中，确保智能体的内部状态与游戏世界保持一致。

        Args:
            dictionary (dict): 包含智能体最新状态信息的字典，来自游戏引擎
        """
        # 检查智能体是否还存活
        if (not dictionary['agentAlive']):
            # 如果智能体死亡，标记存活状态为False
            self.alive = False
            # 注释掉的代码：之前死亡时会将位置设为无穷大，现在改为保持最后位置
            # inf = float('inf')
            # self.location = (inf, inf, inf)
        else:
            # 智能体存活时，更新所有属性
            assert dictionary['valid']  # 确保数据有效

            # 根据预定义的映射关系，将JSON数据更新到本地属性
            for attr_json, attr_agent in self.attrs:
                setattr(self, attr_agent, dictionary[attr_json])

            # 数据一致性检查：确保UID匹配
            # print(self.uid)        # 调试输出：智能体UID
            # print(self.uid_remote) # 调试输出：远程UID
            assert self.uid == self.uid_remote, "UID不匹配，数据可能有误"

            # 更新位置向量表示
            self.pos3d = np.array(self.location)          # 3D位置向量
            self.pos2d = self.pos3d[:2]                   # 2D位置向量（提取x,y）
            self.vel3d = np.array(self.velocity)          # 3D速度向量
            self.vel2d = self.pos3d[:2]                   # 2D速度向量（提取x,y）

            # 更新缩放信息
            self.scale3d = np.array(self.scale3)          # 3D缩放向量
            self.scale = self.scale3[0]                   # 统一缩放比例（假设等比例缩放）

            # 更新朝向信息
            self.yaw = self.rotation[0]                   # 从旋转向量中提取偏航角

            # 标记为存活状态
            self.alive = True

            # 更新队伍信息（防止队伍在游戏中发生变化）
            self.team = dictionary['agentTeam']


# 使用示例和说明：
"""
智能体类的使用流程：

1. 创建智能体：
   agent = Agent(
       team=0,                    # 队伍0（红队）
       team_id=1,                 # 队伍内编号1
       uid=1001,                  # 全局唯一ID
       location=(100, 200, 50),   # 初始位置坐标
       rotation=(0, 90, 0),       # 初始旋转角度
       velocity=(5, 0, 0),        # 初始速度
       health=100,                # 初始生命值
       yaw=90,                    # 偏航角
       speed=20                   # 最大速度
   )

2. 更新智能体状态：
   # 从游戏引擎接收状态数据
   game_state = {
       'agentAlive': True,
       'valid': True,
       'agentLocationArr': [110, 210, 50],
       'agentVelocityArr': [5, 2, 0],
       'agentHp': 95,
       # ... 其他属性
   }

   # 更新智能体状态
   agent.update_agent_attrs(game_state)

3. 访问智能体属性：
   print(f"位置: {agent.pos3d}")
   print(f"生命值: {agent.hp}")
   print(f"存活状态: {agent.alive}")
   print(f"队伍: {agent.team}")
"""